﻿/*
*	移植nginx内存池
*/

#ifndef _NGNIX_MEMORY_POOL_H_
#define _NGNIX_MEMORY_POOL_H_

#include <functional>
#include <memory>

// 全局类型定义
using u_char = unsigned char;
using ngx_uint_t = unsigned int;

// 前置声明
struct ngx_pool_t;

struct ngx_pool_cleanup_t {
    using ngx_pool_cleanup_pt = void(*)(void*);

    ngx_pool_cleanup_pt handler;
    void* data;
    ngx_pool_cleanup_t* next;
};

struct ngx_pool_large_t {
    ngx_pool_large_t* next;
    void* alloc;
};

struct ngx_pool_data_t {
    u_char* last;
    u_char* end;
    ngx_pool_t* next;
    ngx_uint_t failed;
};

struct ngx_pool_t {
    ngx_pool_data_t d;
    size_t max;
    ngx_pool_t* current;
    ngx_pool_large_t* large;
    ngx_pool_cleanup_t* cleanup;
};

class MemoryPool {
public:
    MemoryPool(const size_t size = NGX_DEFAULT_POOL_SIZE);
    ~MemoryPool();

    MemoryPool(const MemoryPool&) = delete;
    MemoryPool& operator=(const MemoryPool&) = delete;

    MemoryPool(MemoryPool&&) = default;
    MemoryPool& operator=(MemoryPool&&) = default;


public: // 成员函数
    void ngx_reset_pool();
    void* ngx_palloc(size_t size);
    void* ngx_pnalloc(size_t size);
    void* ngx_pcalloc(size_t size);
    ngx_pool_cleanup_t* ngx_pool_cleanup_add(size_t size);

private: // 工具函数
    constexpr static ngx_uint_t ngx_align(int data, ngx_uint_t align) { return ((data)+(align - 1)) & ~(align - 1); }
    constexpr u_char* ngx_align_ptr(void* ptr, ngx_uint_t align) { return (u_char*)(((uintptr_t)(ptr)+((uintptr_t)align - 1)) & ~((uintptr_t)align - 1)); }
    bool ngx_create_pool(size_t size);
    void ngx_destroy_pool();
    void* ngx_palloc_small(size_t size, bool align);
    void* ngx_palloc_block(size_t size);
    bool ngx_pfree(void* p);
    void* ngx_alloc(size_t size);
    void* ngx_memalign(ngx_uint_t alignment, size_t size);
    void ngx_free(void* data);
    void* ngx_palloc_large(size_t size);
    void ngx_memzero(void* ptr, size_t size);

private: // 常量定义
     static constexpr ngx_uint_t ngx_pagesize = 4096;
     static constexpr ngx_uint_t NGX_MAX_ALLOC_FROM_POOL = ngx_pagesize - 1;
     static constexpr ngx_uint_t NGX_DEFAULT_POOL_SIZE = 16 * 1024; // 16kb
     static constexpr ngx_uint_t NGX_POOL_ALIGNMENT = 16;
     static constexpr ngx_uint_t NGX_ALIGNMENT = sizeof(unsigned long);    /* platform word */
     //static constexpr ngx_uint_t NGX_MIN_POOL_SIZE = ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)), NGX_POOL_ALIGNMENT);
     static constexpr ngx_uint_t NGX_MIN_POOL_SIZE = ((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t) + NGX_POOL_ALIGNMENT - 1) & ~(NGX_POOL_ALIGNMENT - 1));


private: // 成员变量
    ngx_pool_t* pool_;
};

#endif